package org.anderground.app.controller.algorithms;

import static org.anderground.core.Logger.logBegin;
import static org.anderground.core.Logger.logEnd;

import java.util.Set;

import org.anderground.core.model.Line;
import org.anderground.core.model.ModelData;
import org.anderground.core.model.Station;
import org.anderground.core.model.Transfer;
import org.anderground.core.model.Tunnel;

/**
 * Graph class suitable to use with Dijkstra's shortest path algorithm
 * 
 * Package protected
 * 
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 */
class Graph {

	/**
	 * array of vertices
	 */
	private TwoKeyHashMap<Station, Line, Vertex> verticesMap;

	/**
	 * public constructor
	 * 
	 * @param modelData
	 */
	public Graph(ModelData modelData) {
		logBegin("create new Graph instance");

		Set<Station> stations = modelData.getStations();
		this.verticesMap = new TwoKeyHashMap<Station, Line, Vertex>();
		TwoKeyHashMap<Station, Line, Vertex> verticesMap = this.verticesMap;
		for (Station station : stations) {
			Line[] lines = station.getLines();
			for (Line line : lines) {
				verticesMap.put(station, line, new Vertex(station));
			}
		}

		int edgesCount = 0;
		for (Station station : stations) {
			Line[] lines = station.getLines();
			if (lines.length > 1) {
				for (Line line : lines) {
					Vertex vertex = verticesMap.get(station, line);
					for (Line anotherLine : lines) {
						if (line != anotherLine) {
							new Edge(anotherLine, vertex, verticesMap.get(
									station, anotherLine));
							edgesCount++;
						}
					}
				}
			}
		}

		Set<Tunnel> tunnels = modelData.getTunnels();
		for (Tunnel tunnel : tunnels) {
			Line line = tunnel.getLine();
			new Edge(tunnel, verticesMap.get(tunnel.getFromStation(), line),
					verticesMap.get(tunnel.getToStation(), line));
			edgesCount++;
		}

		Set<Transfer> transfers = modelData.getTransfers();
		for (Transfer transfer : transfers) {
			Station fromStation = transfer.getFromStation();
			Station toStation = transfer.getToStation();
			for (Line fromLine : fromStation.getLines()) {
				for (Line toLine : toStation.getLines()) {
					new Edge(transfer, verticesMap.get(fromStation, fromLine),
							verticesMap.get(toStation, toLine));
					edgesCount++;
				}
			}
		}

		logEnd("graph contruct complete");
	}

	/**
	 * prepares graph to the new calculation
	 */
	public void reset() {
		for (Vertex vertex : this.verticesMap.values()) {
			vertex.reset();
		}
	}

	/**
	 * @return the vertices
	 */
	public TwoKeyHashMap<Station, Line, Vertex> getVerticesHash() {
		return verticesMap;
	}

}
